Completed
Push — master ( 8967bc...e88c19 )
by Rain
02:47
created

Utils.js ➔ htmlToPlain   C

Complexity

Conditions 8
Paths 2

Size

Total Lines 113

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 113
rs 5.2676

1 Function

Rating   Name   Duplication   Size   Complexity  
A Utils.js ➔ ... ➔ ??? 0 5 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
2
import window from 'window';
3
import $ from '$';
4
import _ from '_';
5
import ko from 'ko';
6
import {$win, $div, dropdownVisibility, data as GlobalsData} from 'Common/Globals';
7
import {ComposeType, EventKeyCode, SaveSettingsStep, FolderType} from 'Common/Enums';
8
import {Mime} from 'Common/Mime';
9
10
import Autolinker from 'Autolinker';
11
12
const trim = $.trim;
13
const inArray = $.inArray;
14
const isArray = _.isArray;
15
const isObject = _.isObject;
16
const isFunc = _.isFunction;
17
const isUnd = _.isUndefined;
18
const isNull = _.isNull;
19
const has = _.has;
20
const bind = _.bind;
21
const noop = () => {}; // eslint-disable-line no-empty-function
22
const noopTrue = () => true;
23
const noopFalse = () => false;
24
25
export {trim, inArray, isArray, isObject, isFunc, isUnd, isNull, has, bind, noop, noopTrue, noopFalse};
26
27
/**
28
 * @param {Function} func
29
 */
30
export function silentTryCatch(func)
31
{
32
	try {
33
		func();
34
	}
35
	catch (e) {} // eslint-disable-line no-empty
36
}
37
38
/**
39
 * @param {*} value
40
 * @returns {boolean}
41
 */
42
export function isNormal(value)
43
{
44
	return !isUnd(value) && !isNull(value);
45
}
46
47
/**
48
 * @param {(string|number)} value
49
 * @param {boolean=} includeZero = true
50
 * @returns {boolean}
51
 */
52
export function isPosNumeric(value, includeZero = true)
53
{
54
	return !isNormal(value) ? false :
55
		(includeZero ? (/^[0-9]*$/).test(value.toString()) : (/^[1-9]+[0-9]*$/).test(value.toString()));
56
}
57
58
/**
59
 * @param {*} value
60
 * @param {number=} defaultValur = 0
61
 * @returns {number}
62
 */
63
export function pInt(value, defaultValur = 0)
64
{
65
	const result = isNormal(value) && '' !== value ? window.parseInt(value, 10) : defaultValur;
66
	return window.isNaN(result) ? defaultValur : result;
67
}
68
69
/**
70
 * @param {*} value
71
 * @returns {string}
72
 */
73
export function pString(value)
74
{
75
	return isNormal(value) ? '' + value : '';
76
}
77
78
/**
79
 * @param {*} value
80
 * @returns {boolean}
81
 */
82
export function pBool(value)
83
{
84
	return !!value;
85
}
86
87
/**
88
 * @param {*} value
89
 * @returns {string}
90
 */
91
export function boolToAjax(value)
92
{
93
	return value ? '1' : '0';
94
}
95
96
/**
97
 * @param {*} values
98
 * @returns {boolean}
99
 */
100
export function isNonEmptyArray(values)
101
{
102
	return isArray(values) && 0 < values.length;
103
}
104
105
/**
106
 * @param {string} component
107
 * @returns {string}
108
 */
109
export function encodeURIComponent(component)
110
{
111
	return window.encodeURIComponent(component);
112
}
113
114
/**
115
 * @param {string} component
116
 * @returns {string}
117
 */
118
export function decodeURIComponent(component)
119
{
120
	return window.decodeURIComponent(component);
121
}
122
123
/**
124
 * @param {string} url
125
 * @returns {string}
126
 */
127
export function decodeURI(url)
128
{
129
	return window.decodeURI(url);
130
}
131
132
/**
133
 * @param {string} url
134
 * @returns {string}
135
 */
136
export function encodeURI(url)
137
{
138
	return window.encodeURI(url);
139
}
140
141
/**
142
 * @param {string} queryString
143
 * @returns {Object}
144
 */
145
export function simpleQueryParser(queryString)
146
{
147
	let
148
		index = 0,
149
		len = 0,
150
		temp = null;
0 ignored issues
show
Unused Code introduced by
The assignment to temp seems to be never used. If you intend to free memory here, this is not necessary since the variable leaves the scope anyway.
Loading history...
151
152
	const
153
		queries = queryString.split('&'),
154
		params = {};
155
156
	for (len = queries.length; index < len; index++)
157
	{
158
		temp = queries[index].split('=');
159
		params[decodeURIComponent(temp[0])] = decodeURIComponent(temp[1]);
160
	}
161
162
	return params;
163
}
164
165
/**
166
 * @param {number=} len = 32
167
 * @returns {string}
168
 */
169
export function fakeMd5(len = 32)
170
{
171
	const
172
		line = '0123456789abcdefghijklmnopqrstuvwxyz',
173
		lineLen = line.length;
174
175
	len = pInt(len);
176
177
	let result = '';
178
	while (result.length < len)
179
	{
180
		result += line.substr(window.Math.round(window.Math.random() * lineLen), 1);
181
	}
182
183
	return result;
184
}
185
186
/**
187
 * @param {string} text
188
 * @returns {string}
189
 */
190
export function encodeHtml(text)
191
{
192
	return isNormal(text) ? _.escape(text.toString()) : '';
193
}
194
195
/**
196
 * @param {string} text
197
 * @param {number=} len = 100
198
 * @returns {string}
199
 */
200
export function splitPlainText(text, len = 100)
201
{
202
	let
203
		prefix = '',
204
		subText = '',
205
		result = text,
206
		spacePos = 0,
207
		newLinePos = 0;
208
209
	while (result.length > len)
210
	{
211
		subText = result.substring(0, len);
212
		spacePos = subText.lastIndexOf(' ');
213
		newLinePos = subText.lastIndexOf('\n');
214
215
		if (-1 !== newLinePos)
216
		{
217
			spacePos = newLinePos;
218
		}
219
220
		if (-1 === spacePos)
221
		{
222
			spacePos = len;
223
		}
224
225
		prefix += subText.substring(0, spacePos) + '\n';
226
		result = result.substring(spacePos + 1);
227
	}
228
229
	return prefix + result;
230
}
231
232
const timeOutAction = (function() {
233
	const timeOuts = {};
234
	return (action, fFunction, timeOut) => {
235
		timeOuts[action] = isUnd(timeOuts[action]) ? 0 : timeOuts[action];
236
		window.clearTimeout(timeOuts[action]);
237
		timeOuts[action] = window.setTimeout(fFunction, timeOut);
238
	};
239
}());
240
241
const timeOutActionSecond = (function() {
242
	const timeOuts = {};
243
	return (action, fFunction, timeOut) => {
244
		if (!timeOuts[action])
245
		{
246
			timeOuts[action] = window.setTimeout(() => {
247
				fFunction();
248
				timeOuts[action] = 0;
249
			}, timeOut);
250
		}
251
	};
252
}());
253
254
export {timeOutAction, timeOutActionSecond};
255
256
/**
257
 * @returns {boolean}
258
 */
259
export function inFocus()
260
{
261
	try {
262
		if (window.document.activeElement)
263
		{
264
			if (isUnd(window.document.activeElement.__inFocusCache))
265
			{
266
				window.document.activeElement.__inFocusCache = $(window.document.activeElement).is('input,textarea,iframe,.cke_editable');
267
			}
268
269
			return !!window.document.activeElement.__inFocusCache;
270
		}
271
	}
272
	catch (e) {} // eslint-disable-line no-empty
273
274
	return false;
275
}
276
277
/**
278
 * @param {boolean} force
279
 * @returns {void}
280
 */
281
export function removeInFocus(force)
282
{
283
	if (window.document && window.document.activeElement && window.document.activeElement.blur)
284
	{
285
		try {
286
			const activeEl = $(window.document.activeElement);
287
			if (activeEl && activeEl.is('input,textarea'))
288
			{
289
				window.document.activeElement.blur();
290
			}
291
			else if (force)
292
			{
293
				window.document.activeElement.blur();
294
			}
295
		}
296
		catch (e) {} // eslint-disable-line no-empty
297
	}
298
}
299
300
/**
301
 * @returns {void}
302
 */
303
export function removeSelection()
304
{
305
	try {
306
		if (window && window.getSelection)
307
		{
308
			const sel = window.getSelection();
309
			if (sel && sel.removeAllRanges)
310
			{
311
				sel.removeAllRanges();
312
			}
313
		}
314
		else if (window.document && window.document.selection && window.document.selection.empty)
315
		{
316
			window.document.selection.empty();
317
		}
318
	}
319
	catch (e) {} // eslint-disable-line no-empty
320
}
321
322
/**
323
 * @param {string} prefix
324
 * @param {string} subject
325
 * @returns {string}
326
 */
327
export function replySubjectAdd(prefix, subject)
328
{
329
	prefix = trim(prefix.toUpperCase());
330
	subject = trim(subject.replace(/[\s]+/g, ' '));
331
332
	let drop = false,
333
		re = 'RE' === prefix,
334
		fwd = 'FWD' === prefix;
335
336
	const
337
		parts = [],
338
		prefixIsRe = !fwd;
339
340
	if ('' !== subject)
341
	{
342
		_.each(subject.split(':'), (part) => {
343
			const trimmedPart = trim(part);
344
			if (!drop && ((/^(RE|FWD)$/i).test(trimmedPart) || (/^(RE|FWD)[\[\(][\d]+[\]\)]$/i).test(trimmedPart)))
345
			{
346
				if (!re)
347
				{
348
					re = !!(/^RE/i).test(trimmedPart);
349
				}
350
351
				if (!fwd)
352
				{
353
					fwd = !!(/^FWD/i).test(trimmedPart);
354
				}
355
			}
356
			else
357
			{
358
				parts.push(part);
359
				drop = true;
360
			}
361
		});
362
	}
363
364
	if (prefixIsRe)
365
	{
366
		re = false;
367
	}
368
	else
369
	{
370
		fwd = false;
371
	}
372
373
	return trim(
374
		(prefixIsRe ? 'Re: ' : 'Fwd: ') +
375
		(re ? 'Re: ' : '') +
376
		(fwd ? 'Fwd: ' : '') +
377
		trim(parts.join(':'))
378
	);
379
}
380
381
/**
382
 * @param {number} num
383
 * @param {number} dec
384
 * @returns {number}
385
 */
386
export function roundNumber(num, dec)
387
{
388
	return window.Math.round(num * window.Math.pow(10, dec)) / window.Math.pow(10, dec);
389
}
390
391
/**
392
 * @param {(number|string)} sizeInBytes
393
 * @returns {string}
394
 */
395
export function friendlySize(sizeInBytes)
396
{
397
	sizeInBytes = pInt(sizeInBytes);
398
399
	switch (true)
400
	{
401
		case 1073741824 <= sizeInBytes:
402
			return roundNumber(sizeInBytes / 1073741824, 1) + 'GB';
403
		case 1048576 <= sizeInBytes:
404
			return roundNumber(sizeInBytes / 1048576, 1) + 'MB';
405
		case 1024 <= sizeInBytes:
406
			return roundNumber(sizeInBytes / 1024, 0) + 'KB';
407
		// no default
408
	}
409
410
	return sizeInBytes + 'B';
411
}
412
413
/**
414
 * @param {string} desc
415
 */
416
export function log(desc)
417
{
418
	if (window.console && window.console.log)
419
	{
420
		window.console.log(desc);
421
	}
422
}
423
424
/**
425
 * @param {?} object
426
 * @param {string} methodName
427
 * @param {Array=} params
428
 * @param {number=} delay = 0
429
 */
430
export function delegateRun(object, methodName, params, delay = 0)
431
{
432
	if (object && object[methodName])
433
	{
434
		delay = pInt(delay);
435
		params = isArray(params) ? params : [];
436
437
		if (0 >= delay)
438
		{
439
			object[methodName](...params);
440
		}
441
		else
442
		{
443
			_.delay(() => {
444
				object[methodName](...params);
445
			}, delay);
446
		}
447
	}
448
}
449
450
/**
451
 * @param {?} event
452
 */
453
export function killCtrlACtrlS(event)
454
{
455
	event = event || window.event;
456
	if (event && event.ctrlKey && !event.shiftKey && !event.altKey)
457
	{
458
		const key = event.keyCode || event.which;
459
		if (key === EventKeyCode.S)
460
		{
461
			event.preventDefault();
462
			return;
0 ignored issues
show
Unused Code introduced by
This return has no effect and can be removed.
Loading history...
463
		}
464
		else if (key === EventKeyCode.A)
465
		{
466
			const sender = event.target || event.srcElement;
467
			if (sender && ('true' === '' + sender.contentEditable ||
468
				(sender.tagName && sender.tagName.match(/INPUT|TEXTAREA/i))))
469
			{
470
				return;
471
			}
472
473
			if (window.getSelection)
474
			{
475
				window.getSelection().removeAllRanges();
476
			}
477
			else if (window.document.selection && window.document.selection.clear)
478
			{
479
				window.document.selection.clear();
480
			}
481
482
			event.preventDefault();
483
		}
484
	}
485
}
486
487
/**
488
 * @param {(Object|null|undefined)} context
489
 * @param {Function} fExecute
490
 * @param {(Function|boolean|null)=} fCanExecute = true
491
 * @returns {Function}
492
 */
493
export function createCommand(context, fExecute, fCanExecute = true)
494
{
495
	let fResult = null;
496
	const fNonEmpty = (...args) => {
497
		if (fResult && fResult.canExecute && fResult.canExecute())
498
		{
499
			fExecute.apply(context, args);
500
		}
501
		return false;
502
	};
503
504
	fResult = fExecute ? fNonEmpty : noop;
505
	fResult.enabled = ko.observable(true);
506
507
	if (isFunc(fCanExecute))
508
	{
509
		fResult.canExecute = ko.computed(() => fResult.enabled() && fCanExecute.call(context));
510
	}
511
	else
512
	{
513
		fResult.canExecute = ko.computed(() => fResult.enabled() && !!fCanExecute);
514
	}
515
516
	return fResult;
517
}
518
519
/**
520
 * @param {string} theme
521
 * @returns {string}
522
 */
523
export const convertThemeName = _.memoize((theme) => {
0 ignored issues
show
Unused Code introduced by
The constant convertThemeName seems to be never used. Consider removing it.
Loading history...
524
525
	if ('@custom' === theme.substr(-7))
526
	{
527
		theme = trim(theme.substring(0, theme.length - 7));
528
	}
529
530
	return trim(theme.replace(/[^a-zA-Z0-9]+/g, ' ').replace(/([A-Z])/g, ' $1').replace(/[\s]+/g, ' '));
531
});
532
533
/**
534
 * @param {string} name
535
 * @returns {string}
536
 */
537
export function quoteName(name)
538
{
539
	return name.replace(/["]/g, '\\"');
540
}
541
542
/**
543
 * @returns {number}
544
 */
545
export function microtime()
546
{
547
	return (new window.Date()).getTime();
548
}
549
550
/**
551
 * @returns {number}
552
 */
553
export function timestamp()
554
{
555
	return window.Math.round(microtime() / 1000);
556
}
557
558
/**
559
 *
560
 * @param {string} language
561
 * @param {boolean=} isEng = false
562
 * @returns {string}
563
 */
564
export function convertLangName(language, isEng = false)
565
{
566
	return require('Common/Translator').i18n('LANGS_NAMES' + (true === isEng ? '_EN' : '') + '/LANG_' +
567
		language.toUpperCase().replace(/[^a-zA-Z0-9]+/g, '_'), null, language);
568
}
569
570
/**
571
 * @returns {object}
572
 */
573
export function draggablePlace()
574
{
575
	return $('<div class="draggablePlace">' +
576
		'<span class="text"></span>&nbsp;' +
577
		'<i class="icon-copy icon-white visible-on-ctrl"></i>' +
578
		'<i class="icon-mail icon-white hidden-on-ctrl"></i>' +
579
		'</div>'
580
	).appendTo('#rl-hidden');
581
}
582
583
/**
584
 * @param {object} domOption
0 ignored issues
show
Documentation introduced by
The parameter domOption does not exist. Did you maybe forget to remove this comment?
Loading history...
585
 * @param {object} item
586
 * @returns {void}
587
 */
588
export function defautOptionsAfterRender(domItem, item)
589
{
590
	if (item && !isUnd(item.disabled) && domItem)
591
	{
592
		$(domItem)
593
			.toggleClass('disabled', item.disabled)
594
			.prop('disabled', item.disabled);
595
	}
596
}
597
598
/**
599
 * @param {string} title
0 ignored issues
show
Documentation introduced by
The parameter title does not exist. Did you maybe forget to remove this comment?
Loading history...
600
 * @param {Object} body
601
 * @param {boolean} isHtml
0 ignored issues
show
Documentation introduced by
The parameter isHtml does not exist. Did you maybe forget to remove this comment?
Loading history...
602
 * @param {boolean} print
0 ignored issues
show
Documentation introduced by
The parameter print does not exist. Did you maybe forget to remove this comment?
Loading history...
603
 */
604
export function clearBqSwitcher(body)
605
{
606
	body.find('blockquote.rl-bq-switcher').removeClass('rl-bq-switcher hidden-bq');
607
	body.find('.rlBlockquoteSwitcher').off('.rlBlockquoteSwitcher').remove();
608
	body.find('[data-html-editor-font-wrapper]').removeAttr('data-html-editor-font-wrapper');
609
}
610
611
/**
612
 * @param {string} title
613
 * @param {Object} body
614
 * @param {boolean} isHtml
615
 * @param {boolean} print
616
 */
617
export function previewMessage(title, body, isHtml, print)
618
{
619
	const
620
		win = window.open(''),
621
		doc = win.document,
622
		bodyClone = body.clone(),
623
		bodyClass = isHtml ? 'html' : 'plain';
624
625
	clearBqSwitcher(bodyClone);
626
627
	const html = bodyClone ? bodyClone.html() : '';
628
629
	title = encodeHtml(title);
630
631
	doc.write(`<html>
632
<head>
633
	<meta charset="utf-8" />
634
	<meta name="viewport" content="user-scalable=no" />
635
	<meta name="apple-mobile-web-app-capable" content="yes" />
636
	<meta name="robots" content="noindex, nofollow, noodp" />
637
	<title>${title}</title>
638
	<style>
639
html, body {
640
	background-color: #fff;
641
	font-size: 13px;
642
	font-family: arial, sans-serif;
643
}
644
645
a {color: blue; text-decoration: underline}
646
a:visited {color: #609}
647
a:active {color: red}
648
blockquote {border-left: 2px solid black; margin: 0; padding: 0px 10px}
649
650
pre {
651
	margin: 0px;
652
	padding: 0px;
653
	font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;
654
	background: #fff;
655
	border: none;
656
	white-space: pre-wrap;
657
	word-wrap: break-word;
658
	word-break: break-all;
659
}
660
661
body.html pre {
662
	font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;
663
	white-space: pre-wrap;
664
	word-wrap: break-word;
665
	word-break: normal;
666
}
667
668
body.plain {
669
670
	padding: 15px;
671
	white-space: pre-wrap;
672
	font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;
673
}
674
675
body.plain pre {
676
	margin: 0px;
677
	padding: 0px;
678
	background: #fff;
679
	border: none;
680
	font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;
681
	white-space: pre-wrap;
682
	word-wrap: break-word;
683
	word-break: normal;
684
}
685
686
body.plain blockquote {
687
	border-left: 2px solid blue;
688
	color: blue;
689
}
690
691
body.plain blockquote blockquote {
692
	border-left: 2px solid green;
693
	color: green;
694
}
695
696
body.plain blockquote blockquote blockquote {
697
	border-left: 2px solid red;
698
	color: red;
699
}
700
	</style>
701
</head>
702
<body class="${bodyClass}">${html}</body>
703
</html>`);
704
705
	doc.close();
706
707
	if (print)
708
	{
709
		window.setTimeout(() => win.print(), 100);
710
	}
711
}
712
713
/**
714
 * @param {Function} fCallback
715
 * @param {?} koTrigger
716
 * @param {?} context = null
717
 * @param {number=} timer = 1000
718
 * @returns {Function}
719
 */
720
export function settingsSaveHelperFunction(fCallback, koTrigger, context = null, timer = 1000)
721
{
722
	timer = pInt(timer);
723
	return (type, data, cached, requestAction, requestParameters) => {
724
		koTrigger.call(context, data && data.Result ? SaveSettingsStep.TrueResult : SaveSettingsStep.FalseResult);
725
		if (fCallback)
726
		{
727
			fCallback.call(context, type, data, cached, requestAction, requestParameters);
728
		}
729
		_.delay(() => {
730
			koTrigger.call(context, SaveSettingsStep.Idle);
731
		}, timer);
732
	};
733
}
734
735
/**
736
 * @param {object} koTrigger
737
 * @param {mixed} context
738
 * @returns {mixed}
739
 */
740
export function settingsSaveHelperSimpleFunction(koTrigger, context)
741
{
742
	return settingsSaveHelperFunction(null, koTrigger, context, 1000);
743
}
744
745
/**
746
 * @param {object} remote
747
 * @param {string} settingName
748
 * @param {string} type
749
 * @param {function} fTriggerFunction
750
 * @returns {function}
751
 */
752
export function settingsSaveHelperSubscribeFunction(remote, settingName, type, fTriggerFunction)
753
{
754
	return (value) => {
755
756
		if (remote)
757
		{
758
			switch (type)
759
			{
760
				case 'bool':
761
				case 'boolean':
762
					value = value ? '1' : '0';
763
					break;
764
				case 'int':
765
				case 'integer':
766
				case 'number':
767
					value = pInt(value);
768
					break;
769
				case 'trim':
770
					value = trim(value);
771
					break;
772
				default:
773
					value = pString(value);
774
					break;
775
			}
776
777
			const data = {};
778
			data[settingName] = value;
779
780
			if (remote.saveAdminConfig)
781
			{
782
				remote.saveAdminConfig(fTriggerFunction || null, data);
783
			}
784
			else if (remote.saveSettings)
785
			{
786
				remote.saveSettings(fTriggerFunction || null, data);
787
			}
788
		}
789
	};
790
}
791
792
/**
793
 * @param {string} html
794
 * @returns {string}
795
 */
796
export function findEmailAndLinks(html)
797
{
798
//	return html;
799
	return Autolinker.link(html, {
800
		newWindow: true,
801
		stripPrefix: false,
802
		urls: true,
803
		email: true,
804
		twitter: false,
805
		phone: false,
806
		hashtag: false,
807
		replaceFn: function(autolinker, match) {
808
			return !(autolinker && match && 'url' === match.getType() && match.matchedText && 0 !== match.matchedText.indexOf('http'));
809
		}
810
	});
811
}
812
813
/**
814
 * @param {string} html
815
 * @returns {string}
816
 */
817
export function htmlToPlain(html)
818
{
819
	let
820
		pos = 0,
821
		limit = 0,
822
		iP1 = 0,
823
		iP2 = 0,
824
		iP3 = 0,
825
826
		text = '';
827
828
	const
829
		convertBlockquote = (blockquoteText) => {
830
			blockquoteText = '> ' + trim(blockquoteText).replace(/\n/gm, '\n> ');
831
			return blockquoteText.replace(/(^|\n)([> ]+)/gm,
832
				(...args) => (args && 2 < args.length ? args[1] + trim(args[2].replace(/[\s]/g, '')) + ' ' : ''));
0 ignored issues
show
Bug introduced by
The variable args seems to be never initialized.
Loading history...
introduced by
This code is unreachable and can thus be removed without consequences.
Loading history...
833
		},
834
		convertDivs = (...args) => {
835
			if (args && 1 < args.length)
836
			{
837
				let divText = trim(args[1]);
838
				if (0 < divText.length)
839
				{
840
					divText = divText.replace(/<div[^>]*>([\s\S\r\n]*)<\/div>/gmi, convertDivs);
841
					divText = '\n' + trim(divText) + '\n';
842
				}
843
844
				return divText;
845
			}
846
847
			return '';
848
		},
849
		convertPre = (...args) => (args && 1 < args.length ? args[1].toString().replace(/[\n]/gm, '<br />').replace(/[\r]/gm, '') : ''),
0 ignored issues
show
introduced by
This code is unreachable and can thus be removed without consequences.
Loading history...
Bug introduced by
The variable args seems to be never initialized.
Loading history...
850
		fixAttibuteValue = (...args) => (args && 1 < args.length ? '' + args[1] + _.escape(args[2]) : ''),
0 ignored issues
show
introduced by
This code is unreachable and can thus be removed without consequences.
Loading history...
Bug introduced by
The variable args seems to be never initialized.
Loading history...
851
		convertLinks = (...args) => (args && 1 < args.length ? trim(args[1]) : '');
0 ignored issues
show
Bug introduced by
The variable args seems to be never initialized.
Loading history...
introduced by
This code is unreachable and can thus be removed without consequences.
Loading history...
852
853
	text = html
854
		.replace(/\u0002([\s\S]*)\u0002/gm, '\u200C$1\u200C')
855
		.replace(/<p[^>]*><\/p>/gi, '')
856
		.replace(/<pre[^>]*>([\s\S\r\n\t]*)<\/pre>/gmi, convertPre)
857
		.replace(/[\s]+/gm, ' ')
858
		.replace(/((?:href|data)\s?=\s?)("[^"]+?"|'[^']+?')/gmi, fixAttibuteValue)
859
		.replace(/<br[^>]*>/gmi, '\n')
860
		.replace(/<\/h[\d]>/gi, '\n')
861
		.replace(/<\/p>/gi, '\n\n')
862
		.replace(/<ul[^>]*>/gmi, '\n')
863
		.replace(/<\/ul>/gi, '\n')
864
		.replace(/<li[^>]*>/gmi, ' * ')
865
		.replace(/<\/li>/gi, '\n')
866
		.replace(/<\/td>/gi, '\n')
867
		.replace(/<\/tr>/gi, '\n')
868
		.replace(/<hr[^>]*>/gmi, '\n_______________________________\n\n')
869
		.replace(/<div[^>]*>([\s\S\r\n]*)<\/div>/gmi, convertDivs)
870
		.replace(/<blockquote[^>]*>/gmi, '\n__bq__start__\n')
871
		.replace(/<\/blockquote>/gmi, '\n__bq__end__\n')
872
		.replace(/<a [^>]*>([\s\S\r\n]*?)<\/a>/gmi, convertLinks)
873
		.replace(/<\/div>/gi, '\n')
874
		.replace(/&nbsp;/gi, ' ')
875
		.replace(/&quot;/gi, '"')
876
		.replace(/<[^>]*>/gm, '');
877
878
	text = $div.html(text).text();
879
880
	text = text
881
		.replace(/\n[ \t]+/gm, '\n')
882
		.replace(/[\n]{3,}/gm, '\n\n')
883
		.replace(/&gt;/gi, '>')
884
		.replace(/&lt;/gi, '<')
885
		.replace(/&amp;/gi, '&');
886
887
	text = splitPlainText(trim(text));
888
889
	pos = 0;
890
	limit = 800;
891
892
	while (0 < limit)
893
	{
894
		limit -= 1;
895
		iP1 = text.indexOf('__bq__start__', pos);
896
		if (-1 < iP1)
897
		{
898
			iP2 = text.indexOf('__bq__start__', iP1 + 5);
899
			iP3 = text.indexOf('__bq__end__', iP1 + 5);
900
901
			if ((-1 === iP2 || iP3 < iP2) && iP1 < iP3)
902
			{
903
				text = text.substring(0, iP1) +
904
					convertBlockquote(text.substring(iP1 + 13, iP3)) +
905
					text.substring(iP3 + 11);
906
907
				pos = 0;
908
			}
909
			else if (-1 < iP2 && iP2 < iP3)
910
			{
911
				pos = iP2 - 1;
912
			}
913
			else
914
			{
915
				pos = 0;
916
			}
917
		}
918
		else
919
		{
920
			break;
921
		}
922
	}
923
924
	text = text
925
		.replace(/__bq__start__/gm, '')
926
		.replace(/__bq__end__/gm, '');
927
928
	return text;
929
}
930
931
/**
932
 * @param {string} plain
933
 * @param {boolean} findEmailAndLinksInText = false
934
 * @returns {string}
935
 */
936
export function plainToHtml(plain, findEmailAndLinksInText = false)
937
{
938
	plain = plain.toString().replace(/\r/g, '');
939
	plain = plain.replace(/^>[> ]>+/gm, ([match]) => (match ? match.replace(/[ ]+/g, '') : match));
0 ignored issues
show
Bug introduced by
The variable match seems to be never initialized.
Loading history...
introduced by
This code is unreachable and can thus be removed without consequences.
Loading history...
940
941
	let
942
		bIn = false,
943
		bDo = true,
0 ignored issues
show
Unused Code introduced by
The assignment to variable bDo seems to be never used. Consider removing it.
Loading history...
944
		bStart = true,
0 ignored issues
show
Unused Code introduced by
The assignment to variable bStart seems to be never used. Consider removing it.
Loading history...
945
		aNextText = [],
0 ignored issues
show
Unused Code introduced by
The assignment to variable aNextText seems to be never used. Consider removing it.
Loading history...
946
		sLine = '',
947
		iIndex = 0,
948
		aText = plain.split('\n');
949
950
	do
951
	{
952
		bDo = false;
953
		aNextText = [];
954
		for (iIndex = 0; iIndex < aText.length; iIndex++)
955
		{
956
			sLine = aText[iIndex];
957
			bStart = '>' === sLine.substr(0, 1);
958
			if (bStart && !bIn)
959
			{
960
				bDo = true;
961
				bIn = true;
962
				aNextText.push('~~~blockquote~~~');
963
				aNextText.push(sLine.substr(1));
964
			}
965
			else if (!bStart && bIn)
966
			{
967
				if ('' !== sLine)
968
				{
969
					bIn = false;
970
					aNextText.push('~~~/blockquote~~~');
971
					aNextText.push(sLine);
972
				}
973
				else
974
				{
975
					aNextText.push(sLine);
976
				}
977
			}
978
			else if (bStart && bIn)
979
			{
980
				aNextText.push(sLine.substr(1));
981
			}
982
			else
983
			{
984
				aNextText.push(sLine);
985
			}
986
		}
987
988
		if (bIn)
989
		{
990
			bIn = false;
991
			aNextText.push('~~~/blockquote~~~');
992
		}
993
994
		aText = aNextText;
995
	}
996
	while (bDo);
997
998
	plain = aText.join('\n');
999
1000
	plain = plain
1001
//			.replace(/~~~\/blockquote~~~\n~~~blockquote~~~/g, '\n')
1002
		.replace(/&/g, '&amp;')
1003
		.replace(/>/g, '&gt;').replace(/</g, '&lt;')
1004
		.replace(/~~~blockquote~~~[\s]*/g, '<blockquote>')
1005
		.replace(/[\s]*~~~\/blockquote~~~/g, '</blockquote>')
1006
		.replace(/\u200C([\s\S]*)\u200C/g, '\u0002$1\u0002')
1007
		.replace(/\n/g, '<br />');
1008
1009
	return findEmailAndLinksInText ? findEmailAndLinks(plain) : plain;
1010
}
1011
1012
window['rainloop_Utils_htmlToPlain'] = htmlToPlain; // eslint-disable-line dot-notation
1013
window['rainloop_Utils_plainToHtml'] = plainToHtml; // eslint-disable-line dot-notation
1014
1015
/**
1016
 * @param {Array} aSystem
1017
 * @param {Array} aList
1018
 * @param {Array=} aDisabled
1019
 * @param {Array=} aHeaderLines
1020
 * @param {?number=} iUnDeep
1021
 * @param {Function=} fDisableCallback
1022
 * @param {Function=} fVisibleCallback
1023
 * @param {Function=} fRenameCallback
1024
 * @param {boolean=} bSystem
1025
 * @param {boolean=} bBuildUnvisible
1026
 * @returns {Array}
1027
 */
1028
export function folderListOptionsBuilder(aSystem, aList, aDisabled, aHeaderLines,
1029
	iUnDeep, fDisableCallback, fVisibleCallback, fRenameCallback, bSystem, bBuildUnvisible)
1030
{
1031
	let
1032
		/**
1033
		 * @type {?FolderModel}
1034
		 */
1035
		oItem = null,
0 ignored issues
show
Unused Code introduced by
The assignment to oItem seems to be never used. If you intend to free memory here, this is not necessary since the variable leaves the scope anyway.
Loading history...
1036
		bSep = false,
0 ignored issues
show
Unused Code introduced by
The assignment to variable bSep seems to be never used. Consider removing it.
Loading history...
1037
		iIndex = 0,
1038
		iLen = 0,
1039
		aResult = [];
1040
1041
	const sDeepPrefix = '\u00A0\u00A0\u00A0';
1042
1043
	bBuildUnvisible = isUnd(bBuildUnvisible) ? false : !!bBuildUnvisible;
1044
	bSystem = !isNormal(bSystem) ? 0 < aSystem.length : bSystem;
1045
	iUnDeep = !isNormal(iUnDeep) ? 0 : iUnDeep;
1046
	fDisableCallback = isNormal(fDisableCallback) ? fDisableCallback : null;
1047
	fVisibleCallback = isNormal(fVisibleCallback) ? fVisibleCallback : null;
1048
	fRenameCallback = isNormal(fRenameCallback) ? fRenameCallback : null;
1049
1050
	if (!isArray(aDisabled))
1051
	{
1052
		aDisabled = [];
1053
	}
1054
1055
	if (!isArray(aHeaderLines))
1056
	{
1057
		aHeaderLines = [];
1058
	}
1059
1060
	for (iIndex = 0, iLen = aHeaderLines.length; iIndex < iLen; iIndex++)
1061
	{
1062
		aResult.push({
1063
			id: aHeaderLines[iIndex][0],
1064
			name: aHeaderLines[iIndex][1],
1065
			system: false,
1066
			seporator: false,
1067
			disabled: false
1068
		});
1069
	}
1070
1071
	bSep = true;
1072
	for (iIndex = 0, iLen = aSystem.length; iIndex < iLen; iIndex++)
1073
	{
1074
		oItem = aSystem[iIndex];
1075
		if (fVisibleCallback ? fVisibleCallback(oItem) : true)
1076
		{
1077
			if (bSep && 0 < aResult.length)
1078
			{
1079
				aResult.push({
1080
					id: '---',
1081
					name: '---',
1082
					system: false,
1083
					seporator: true,
1084
					disabled: true
1085
				});
1086
			}
1087
1088
			bSep = false;
1089
			aResult.push({
1090
				id: oItem.fullNameRaw,
1091
				name: fRenameCallback ? fRenameCallback(oItem) : oItem.name(),
1092
				system: true,
1093
				seporator: false,
1094
				disabled: !oItem.selectable || -1 < inArray(oItem.fullNameRaw, aDisabled) ||
1095
					(fDisableCallback ? fDisableCallback(oItem) : false)
1096
			});
1097
		}
1098
	}
1099
1100
	bSep = true;
1101
	for (iIndex = 0, iLen = aList.length; iIndex < iLen; iIndex++)
1102
	{
1103
		oItem = aList[iIndex];
1104
//			if (oItem.subScribed() || !oItem.existen || bBuildUnvisible)
1105
		if ((oItem.subScribed() || !oItem.existen || bBuildUnvisible) && (oItem.selectable || oItem.hasSubScribedSubfolders()))
1106
		{
1107
			if (fVisibleCallback ? fVisibleCallback(oItem) : true)
1108
			{
1109
				if (FolderType.User === oItem.type() || !bSystem || oItem.hasSubScribedSubfolders())
1110
				{
1111
					if (bSep && 0 < aResult.length)
1112
					{
1113
						aResult.push({
1114
							id: '---',
1115
							name: '---',
1116
							system: false,
1117
							seporator: true,
1118
							disabled: true
1119
						});
1120
					}
1121
1122
					bSep = false;
1123
					aResult.push({
1124
						id: oItem.fullNameRaw,
1125
						name: (new window.Array(oItem.deep + 1 - iUnDeep)).join(sDeepPrefix) +
1126
							(fRenameCallback ? fRenameCallback(oItem) : oItem.name()),
1127
						system: false,
1128
						seporator: false,
1129
						disabled: !oItem.selectable || -1 < inArray(oItem.fullNameRaw, aDisabled) ||
1130
							(fDisableCallback ? fDisableCallback(oItem) : false)
1131
					});
1132
				}
1133
			}
1134
		}
1135
1136
		if (oItem.subScribed() && 0 < oItem.subFolders().length)
1137
		{
1138
			aResult = aResult.concat(folderListOptionsBuilder([], oItem.subFolders(), aDisabled, [],
1139
				iUnDeep, fDisableCallback, fVisibleCallback, fRenameCallback, bSystem, bBuildUnvisible));
1140
		}
1141
	}
1142
1143
	return aResult;
1144
}
1145
1146
/**
1147
 * @param {object} element
1148
 * @returns {void}
1149
 */
1150
export function selectElement(element)
1151
{
1152
	let
1153
		sel = null,
0 ignored issues
show
Unused Code introduced by
The assignment to sel seems to be never used. If you intend to free memory here, this is not necessary since the variable leaves the scope anyway.
Loading history...
1154
		range = null;
0 ignored issues
show
Unused Code introduced by
The assignment to range seems to be never used. If you intend to free memory here, this is not necessary since the variable leaves the scope anyway.
Loading history...
1155
1156
	if (window.getSelection)
1157
	{
1158
		sel = window.getSelection();
1159
		sel.removeAllRanges();
1160
		range = window.document.createRange();
1161
		range.selectNodeContents(element);
1162
		sel.addRange(range);
1163
	}
1164
	else if (window.document.selection)
1165
	{
1166
		range = window.document.body.createTextRange();
1167
		range.moveToElementText(element);
1168
		range.select();
1169
	}
1170
}
1171
1172
export const detectDropdownVisibility = _.debounce(() => {
0 ignored issues
show
Unused Code introduced by
The constant detectDropdownVisibility seems to be never used. Consider removing it.
Loading history...
1173
	dropdownVisibility(!!_.find(GlobalsData.aBootstrapDropdowns, (item) => item.hasClass('open')));
1174
}, 50);
1175
1176
/**
1177
 * @param {boolean=} delay = false
1178
 */
1179
export function triggerAutocompleteInputChange(delay = false) {
1180
1181
	const fFunc = () => {
1182
		$('.checkAutocomplete').trigger('change');
1183
	};
1184
1185
	if (delay)
1186
	{
1187
		_.delay(fFunc, 100);
1188
	}
1189
	else
1190
	{
1191
		fFunc();
1192
	}
1193
}
1194
1195
const configurationScriptTagCache = {};
1196
1197
/**
1198
 * @param {string} configuration
1199
 * @returns {object}
1200
 */
1201
export function getConfigurationFromScriptTag(configuration)
1202
{
1203
	if (!configurationScriptTagCache[configuration])
1204
	{
1205
		configurationScriptTagCache[configuration] = $('script[type="application/json"][data-configuration="' + configuration + '"]');
1206
	}
1207
1208
	try
1209
	{
1210
		return JSON.parse(configurationScriptTagCache[configuration].text());
1211
	}
1212
	catch (e) {} // eslint-disable-line no-empty
1213
1214
	return {};
1215
}
1216
1217
/**
1218
 * @param {mixed} mPropOrValue
0 ignored issues
show
Documentation introduced by
The parameter mPropOrValue does not exist. Did you maybe forget to remove this comment?
Loading history...
1219
 * @param {mixed} value
1220
 */
1221
export function disposeOne(propOrValue, value)
1222
{
1223
	const disposable = value || propOrValue;
1224
	if (disposable && 'function' === typeof disposable.dispose)
1225
	{
1226
		disposable.dispose();
1227
	}
1228
}
1229
1230
/**
1231
 * @param {Object} object
1232
 */
1233
export function disposeObject(object)
1234
{
1235
	if (object)
1236
	{
1237
		if (isArray(object.disposables))
1238
		{
1239
			_.each(object.disposables, disposeOne);
1240
		}
1241
1242
		ko.utils.objectForEach(object, disposeOne);
1243
	}
1244
}
1245
1246
/**
1247
 * @param {Object|Array} objectOrObjects
1248
 * @returns {void}
1249
 */
1250
export function delegateRunOnDestroy(objectOrObjects)
1251
{
1252
	if (objectOrObjects)
1253
	{
1254
		if (isArray(objectOrObjects))
1255
		{
1256
			_.each(objectOrObjects, (item) => {
1257
				delegateRunOnDestroy(item);
1258
			});
1259
		}
1260
		else if (objectOrObjects && objectOrObjects.onDestroy)
1261
		{
1262
			objectOrObjects.onDestroy();
1263
		}
1264
	}
1265
}
1266
1267
/**
1268
 * @param {object} $styleTag
1269
 * @param {string} css
1270
 * @returns {boolean}
1271
 */
1272
export function appendStyles($styleTag, css)
1273
{
1274
	if ($styleTag && $styleTag[0])
1275
	{
1276
		if ($styleTag[0].styleSheet && !isUnd($styleTag[0].styleSheet.cssText))
1277
		{
1278
			$styleTag[0].styleSheet.cssText = css;
1279
		}
1280
		else
1281
		{
1282
			$styleTag.text(css);
1283
		}
1284
1285
		return true;
1286
	}
1287
1288
	return false;
1289
}
1290
1291
let
1292
	__themeTimer = 0,
1293
	__themeAjax = null;
1294
1295
/**
1296
 * @param {string} value
1297
 * @param {function} themeTrigger
1298
 * @returns {void}
1299
 */
1300
export function changeTheme(value, themeTrigger)
1301
{
1302
	const
1303
		themeLink = $('#app-theme-link'),
1304
		clearTimer = () => {
1305
			__themeTimer = window.setTimeout(() => themeTrigger(SaveSettingsStep.Idle), 1000);
1306
			__themeAjax = null;
1307
		};
1308
1309
	let
1310
		themeStyle = $('#app-theme-style'),
1311
		url = themeLink.attr('href');
1312
1313
	if (!url)
1314
	{
1315
		url = themeStyle.attr('data-href');
1316
	}
1317
1318
	if (url)
1319
	{
1320
		url = url.toString().replace(/\/-\/[^\/]+\/\-\//, '/-/' + value + '/-/');
1321
		url = url.toString().replace(/\/Css\/[^\/]+\/User\//, '/Css/0/User/');
1322
		url = url.toString().replace(/\/Hash\/[^\/]+\//, '/Hash/-/');
1323
1324
		if ('Json/' !== url.substring(url.length - 5, url.length))
1325
		{
1326
			url += 'Json/';
1327
		}
1328
1329
		window.clearTimeout(__themeTimer);
1330
		themeTrigger(SaveSettingsStep.Animate);
1331
1332
		if (__themeAjax && __themeAjax.abort)
1333
		{
1334
			__themeAjax.abort();
1335
		}
1336
1337
		__themeAjax = $.ajax({
1338
			url: url,
1339
			dataType: 'json'
1340
		}).then((data) => {
1341
1342
			if (data && isArray(data) && 2 === data.length)
1343
			{
1344
				if (themeLink && themeLink[0] && (!themeStyle || !themeStyle[0]))
1345
				{
1346
					themeStyle = $('<style id="app-theme-style"></style>');
1347
					themeLink.after(themeStyle);
1348
					themeLink.remove();
1349
				}
1350
1351
				if (themeStyle && themeStyle[0])
1352
				{
1353
					if (appendStyles(themeStyle, data[1]))
1354
					{
1355
						themeStyle.attr('data-href', url).attr('data-theme', data[0]);
1356
					}
1357
				}
1358
1359
				themeTrigger(SaveSettingsStep.TrueResult);
1360
			}
1361
1362
		}).then(clearTimer, clearTimer);
1363
	}
1364
}
1365
1366
/**
1367
 * @returns {function}
1368
 */
1369
export function computedPagenatorHelper(koCurrentPage, koPageCount)
1370
{
1371
	return () => {
1372
1373
		const
1374
			currentPage = koCurrentPage(),
1375
			pageCount = koPageCount(),
1376
			result = [],
1377
			fAdd = (index, push = true, customName = '') => {
1378
1379
				const data = {
1380
					current: index === currentPage,
1381
					name: '' === customName ? index.toString() : customName.toString(),
1382
					custom: '' !== customName,
1383
					title: '' === customName ? '' : index.toString(),
1384
					value: index.toString()
1385
				};
1386
1387
				if (push)
1388
				{
1389
					result.push(data);
1390
				}
1391
				else
1392
				{
1393
					result.unshift(data);
1394
				}
1395
			};
1396
1397
		let
1398
			prev = 0,
1399
			next = 0,
1400
			limit = 2;
1401
1402
		if (1 < pageCount || (0 < pageCount && pageCount < currentPage))
1403
		{
1404
			if (pageCount < currentPage)
1405
			{
1406
				fAdd(pageCount);
1407
				prev = pageCount;
1408
				next = pageCount;
1409
			}
1410
			else
1411
			{
1412
				if (3 >= currentPage || pageCount - 2 <= currentPage)
1413
				{
1414
					limit += 2;
1415
				}
1416
1417
				fAdd(currentPage);
1418
				prev = currentPage;
1419
				next = currentPage;
1420
			}
1421
1422
			while (0 < limit) {
1423
1424
				prev -= 1;
1425
				next += 1;
1426
1427
				if (0 < prev)
1428
				{
1429
					fAdd(prev, false);
1430
					limit -= 1;
1431
				}
1432
1433
				if (pageCount >= next)
1434
				{
1435
					fAdd(next, true);
1436
					limit -= 1;
1437
				}
1438
				else if (0 >= prev)
1439
				{
1440
					break;
1441
				}
1442
			}
1443
1444
			if (3 === prev)
1445
			{
1446
				fAdd(2, false);
1447
			}
1448
			else if (3 < prev)
1449
			{
1450
				fAdd(Math.round((prev - 1) / 2), false, '...');
1451
			}
1452
1453
			if (pageCount - 2 === next)
1454
			{
1455
				fAdd(pageCount - 1, true);
1456
			}
1457
			else if (pageCount - 2 > next)
1458
			{
1459
				fAdd(Math.round((pageCount + next) / 2), true, '...');
1460
			}
1461
1462
			// first and last
1463
			if (1 < prev)
1464
			{
1465
				fAdd(1, false);
1466
			}
1467
1468
			if (pageCount > next)
1469
			{
1470
				fAdd(pageCount, true);
1471
			}
1472
		}
1473
1474
		return result;
1475
	};
1476
}
1477
1478
/**
1479
 * @param {string} fileName
1480
 * @returns {string}
1481
 */
1482
export function getFileExtension(fileName)
1483
{
1484
	fileName = trim(fileName).toLowerCase();
1485
1486
	const result = fileName.split('.').pop();
1487
	return result === fileName ? '' : result;
1488
}
1489
1490
/**
1491
 * @param {string} fileName
1492
 * @returns {string}
1493
 */
1494
export function mimeContentType(fileName)
1495
{
1496
	let
1497
		ext = '',
1498
		result = 'application/octet-stream';
1499
1500
	fileName = trim(fileName).toLowerCase();
1501
1502
	if ('winmail.dat' === fileName)
1503
	{
1504
		return 'application/ms-tnef';
1505
	}
1506
1507
	ext = getFileExtension(fileName);
1508
	if (ext && 0 < ext.length && !isUnd(Mime[ext]))
1509
	{
1510
		result = Mime[ext];
1511
	}
1512
1513
	return result;
1514
}
1515
1516
/**
1517
 * @param {string} url
1518
 * @param {number} value
1519
 * @param {Function} fCallback
1520
 */
1521
export function resizeAndCrop(url, value, fCallback)
1522
{
1523
	const img = new Image();
1524
	img.onload = function() {
1525
1526
		let
1527
			diff = [0, 0];
0 ignored issues
show
Unused Code introduced by
The assignment to variable diff seems to be never used. Consider removing it.
Loading history...
1528
1529
		const
1530
			canvas = window.document.createElement('canvas'),
1531
			ctx = canvas.getContext('2d');
1532
1533
		canvas.width = value;
1534
		canvas.height = value;
1535
1536
		if (this.width > this.height)
1537
		{
1538
			diff = [this.width - this.height, 0];
1539
		}
1540
		else
1541
		{
1542
			diff = [0, this.height - this.width];
1543
		}
1544
1545
		ctx.fillStyle = '#fff';
1546
		ctx.fillRect(0, 0, value, value);
1547
		ctx.drawImage(this, diff[0] / 2, diff[1] / 2, this.width - diff[0], this.height - diff[1], 0, 0, value, value);
1548
1549
		fCallback(canvas.toDataURL('image/jpeg'));
1550
	};
1551
1552
	img.src = url;
1553
}
1554
1555
/**
1556
 * @param {string} mailToUrl
1557
 * @param {Function} PopupComposeVoreModel
1558
 * @returns {boolean}
1559
 */
1560
export function mailToHelper(mailToUrl, PopupComposeVoreModel)
1561
{
1562
	if (mailToUrl && 'mailto:' === mailToUrl.toString().substr(0, 7).toLowerCase())
1563
	{
1564
		if (!PopupComposeVoreModel)
1565
		{
1566
			return true;
1567
		}
1568
1569
		mailToUrl = mailToUrl.toString().substr(7);
1570
1571
		let
1572
			to = [],
0 ignored issues
show
Unused Code introduced by
The assignment to variable to seems to be never used. Consider removing it.
Loading history...
1573
			cc = null,
1574
			bcc = null,
1575
			params = {};
0 ignored issues
show
Unused Code introduced by
The assignment to variable params seems to be never used. Consider removing it.
Loading history...
1576
1577
		const
1578
			email = mailToUrl.replace(/\?.+$/, ''),
1579
			query = mailToUrl.replace(/^[^\?]*\?/, ''),
1580
			EmailModel = require('Model/Email').default,
1581
			emailObj = new EmailModel(),
1582
			fParseEmailLine = (line) => (line ? _.compact(_.map(decodeURIComponent(line).split(/[,]/), (item) => {
0 ignored issues
show
introduced by
This code is unreachable and can thus be removed without consequences.
Loading history...
Bug introduced by
The variable line seems to be never initialized.
Loading history...
1583
				emailObj.clear();
1584
				emailObj.mailsoParse(item);
1585
				return '' !== emailObj.email ? emailObj : null;
1586
			})) : null);
1587
1588
		to = fParseEmailLine(email);
1589
		params = simpleQueryParser(query);
1590
1591
		if (!isUnd(params.cc))
1592
		{
1593
			cc = fParseEmailLine(decodeURIComponent(params.cc));
1594
		}
1595
1596
		if (!isUnd(params.bcc))
1597
		{
1598
			bcc = fParseEmailLine(decodeURIComponent(params.bcc));
1599
		}
1600
1601
		require('Knoin/Knoin').showScreenPopup(PopupComposeVoreModel, [
1602
			ComposeType.Empty, null, to, cc, bcc,
1603
			isUnd(params.subject) ? null : pString(decodeURIComponent(params.subject)),
1604
			isUnd(params.body) ? null : plainToHtml(pString(decodeURIComponent(params.body)))
1605
		]);
1606
1607
		return true;
1608
	}
1609
1610
	return false;
1611
}
1612
1613
export const windowResize = _.debounce((timeout) => {
1614
	if (isUnd(timeout) || isNull(timeout))
1615
	{
1616
		$win.resize();
1617
	}
1618
	else
1619
	{
1620
		window.setTimeout(() => {
1621
			$win.resize();
1622
		}, timeout);
1623
	}
1624
}, 50);
1625
1626
/**
1627
 * @returns {void}
1628
 */
1629
export function windowResizeCallback()
1630
{
1631
	windowResize();
1632
}
1633
1634
let substr = window.String.substr;
1635
if ('b' !== 'ab'.substr(-1))
1636
{
1637
	substr = (str, start, length) => {
1638
		start = 0 > start ? str.length + start : start;
1639
		return str.substr(start, length);
1640
	};
1641
1642
	window.String.substr = substr;
1643
}
1644